package cn.com.chengmandian.bike.service.impl;

import cn.com.chengmandian.agent.utils.ServletUtil;
import cn.com.chengmandian.bike.dto.MemberAuthForm;
import cn.com.chengmandian.bike.dto.MemberInfoUpdateForm;
import cn.com.chengmandian.bike.model.*;
import cn.com.chengmandian.bike.mapper.EbMemberInfoMapper;
import cn.com.chengmandian.bike.model.vo.MemberComboRecordVo;
import cn.com.chengmandian.bike.service.*;
import cn.com.chengmandian.core.common.constants.CommonConstant;
import cn.com.chengmandian.core.common.constants.ResponseCode;
import cn.com.chengmandian.core.common.enums.ClientsEnum;
import cn.com.chengmandian.core.common.enums.UserTypeEnum;
import cn.com.chengmandian.core.common.utils.BillNoUtil;
import cn.com.chengmandian.core.redis.cache.AgentParamCacheService;
import cn.com.chengmandian.core.web.exceptions.BadResponseException;
import cn.com.chengmandian.core.web.pojo.AgentInfo;
import cn.com.chengmandian.core.web.pojo.AgentUser;
import cn.com.chengmandian.core.web.pojo.BikeAreaParam;
import cn.com.chengmandian.core.web.pojo.BikeParam;
import cn.com.chengmandian.core.web.utils.AgentTokenUtil;
import cn.com.chengmandian.core.web.utils.LocalMapUtil;
import cn.com.chengmandian.service.bike.constants.RideOrderStatusEnum;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 电单车会员表 服务实现类
 * </p>
 *
 * @author AutoGenerator
 * @since 2021-12-08
 */
@Service
public class EbMemberInfoServiceImpl extends ServiceImpl<EbMemberInfoMapper, EbMemberInfo> implements IEbMemberInfoService {

    @Autowired
    private IEbMemberCouponService memberCouponService;

    @Autowired
    private IEbDepositConfigService depositConfigService;

    @Autowired
    private IEbMemberDepositService memberDepositService;

    @Autowired
    private IEbPriceRuleService priceRuleService;

    @Autowired
    private IEbMemberWalletService memberWalletService;

    @Autowired
    private IEbRideOrderService rideOrderService;

    @Autowired
    private IEbMemberBlackService memberBlackService;

    @Autowired
    private IEbMemberRegisterService memberRegisterService;

    @Autowired
    private IEbSettingArticleService settingArticleService;

    @Autowired
    private AgentParamCacheService agentParamCacheService;

    @Autowired
    private IEbMemberComboRecordService memberComboRecordService;

    @Autowired
    private IEbMemberCardService memberCardService;

    @Autowired
    private IEbMemberFaceService memberFaceService;
  /**
     * 用户实名认证判断
     * @param agentUser
     * @return
     */
    private EbMemberInfo getEbMemberInfo(AgentUser agentUser, Integer agentId, Integer areaId) {
        EbMemberInfo memberInfo = this.getById(agentUser.getId());
        //人工认证用户无需实名认证
        if(memberInfo.getManualAuth()  != null && memberInfo.getManualAuth() == 1){
            return memberInfo;
        }

        BikeAreaParam bikeAreaParam = agentParamCacheService.getParam(agentId, areaId);
        // 按品牌配置
        if(bikeAreaParam == null || bikeAreaParam.getUserRideAuthNameType() == null || bikeAreaParam.getUserRideAuthNameType().equals(CommonConstant.ONE)) {
            BikeParam bikeParam = agentParamCacheService.getParam(agentId);
            if ((bikeParam == null || (!bikeParam.getUserAgentMiniLoginFaceAuthEnabled() && bikeParam.getUserAgentRideRealNameAuthEnabled()))
                    && !CommonConstant.ONE.equals(memberInfo.getManualAuth())) {
                if (StrUtil.isBlank(memberInfo.getName()) || StrUtil.isBlank(memberInfo.getIdCard())) {
                    throw new BadResponseException(501, "请先实名认证");
                }
            } else {
                if (bikeParam != null && bikeParam.getUserAgentMiniLoginFaceAuthEnabled() && (StrUtil.isBlank(memberInfo.getName()) || StrUtil.isBlank(memberInfo.getIdCard()))
                        && (memberInfo.getIsFace() == null || memberInfo.getIsFace().equals(CommonConstant.ZERO)) && !CommonConstant.ONE.equals(memberInfo.getManualAuth())) {
                    throw new BadResponseException(520, "请先人脸识别实名认证");
                }
            }
            if (bikeParam == null || bikeParam.getUserAgentMiniLoginFaceAuthEnabled() || bikeParam.getUserAgentRideRealNameAuthEnabled()) {
                Assert.isTrue(CommonConstant.ONE.equals(memberInfo.getManualAuth()) || IdcardUtil.getAgeByIdCard(memberInfo.getIdCard()) >= 16, "需要年满16周岁");
            }
        } else {

            // 按用户配置 且要求实名认证
            if(bikeAreaParam != null && bikeAreaParam.getUserRideAuthNameType() != null && bikeAreaParam.getUserRideAuthNameType().equals(CommonConstant.TWO)) {
                if (StrUtil.isBlank(memberInfo.getName()) || StrUtil.isBlank(memberInfo.getIdCard())) {
                    throw new BadResponseException(501, "请先实名认证");
                }
                Assert.isTrue(CommonConstant.ONE.equals(memberInfo.getManualAuth()) || IdcardUtil.getAgeByIdCard(memberInfo.getIdCard()) >= 16, "需要年满16周岁");
            }
        }
        return memberInfo;
    }

    @Override
    public void checkOpenBike(AgentUser agentUser, Integer agentId, Integer areaId) {
        if(agentUser == null){
            throw new BadResponseException(ResponseCode.TOKEN_INVALID,"请先登录");
        }

        //通过用户id判断用户是否被拉黑
        EbMemberBlack ebMemberBlack = memberBlackService.getOne(new LambdaQueryWrapper<EbMemberBlack>()
                .eq(EbMemberBlack::getMemberId, agentUser.getId())
                .eq(EbMemberBlack::getIsDeleted,CommonConstant.ZERO)
                .last("limit 1"));
        if(ebMemberBlack != null && ebMemberBlack.getExpireTime() == null){
            throw new BadResponseException(506,"该用户账号已被拉黑,请联系客服!");
        }
        if(ebMemberBlack != null && ebMemberBlack.getExpireTime() != null && (new Date()).getTime() <=  ebMemberBlack.getExpireTime().getTime()){
            throw new BadResponseException(506,"该用户账号在【"+ DateUtil.format(ebMemberBlack.getExpireTime(),"yyyy-MM-dd")+"】之前已被禁止使用,请联系客服!");
        }
        EbMemberInfo ebMemberInfo = this.getById(agentUser.getId());
        if(ebMemberInfo == null || ebMemberInfo.getIsDeleted() == 1 || ebMemberInfo.getIsEnabled() == 0 || ebMemberInfo.getIsOff() == 1){
            throw new BadResponseException(ResponseCode.TOKEN_INVALID,"请先登录");
        }
        memberBlackService.checkPhone(ebMemberInfo.getMobile());
        // 检验身份证号
        memberBlackService.checkIdCard(ebMemberInfo.getIdCard());
        //实名认证检测
        EbMemberInfo memberInfo = this.getEbMemberInfo(agentUser, agentId, areaId);

        // 押金检查
        EbDepositConfig depositConfig = depositConfigService.getConfig(areaId);
        EbMemberDeposit ebMemberDeposit = memberDepositService.getMemberAvailableRecord(areaId, memberInfo.getId());
        if (depositConfig.getIsForce().equals(CommonConstant.ONE)) {
            if (ebMemberDeposit == null) {
                throw new BadResponseException(502, "请先购买免押卡");
            }
        } else {
            if (ebMemberDeposit == null && (depositConfig.getDepositMoney().compareTo(new BigDecimal(0)) > 0 && memberInfo.getIsDeposit().equals(CommonConstant.ZERO))) {
                throw new BadResponseException(502, "请先缴纳押金");
            }
        }

        // 会员卡检查
        BikeAreaParam bikeAreaParam = agentParamCacheService.getParam(agentId, areaId);
        // 免费账号不用购买会员卡
        if(!memberInfo.getLevel().equals(CommonConstant.TWO)) {
            if (bikeAreaParam != null && bikeAreaParam.getUserRideBuyMemberCard()) {
                MemberComboRecordVo memberComboRecord = memberComboRecordService.getMemberAvailableRecord(areaId, agentUser.getId());
                if (memberComboRecord == null) {
                    throw new BadResponseException(515, "请先购买会员卡");
                }
            }
        }

        //普通账号余额不能0
        if(memberInfo.getLevel().equals(CommonConstant.ONE)){
            EbPriceRule priceRule = priceRuleService.getRule(areaId);

            EbMemberWallet memberWallet = memberWalletService.getMemberWallet(agentUser.getId());
            if (memberWallet.getMoney().compareTo(priceRule.getRidingMinMoney()) < 0) {
                throw new BadResponseException(503, "账户余额不足，请确保账户有" + priceRule.getRidingMinMoney().doubleValue() + "元余额");
            }
        }

        if (rideOrderService.count(new LambdaQueryWrapper<EbRideOrder>().eq(EbRideOrder::getMemberId, agentUser.getId())
                .in(EbRideOrder::getStatus, RideOrderStatusEnum.RIDING.getCode(), RideOrderStatusEnum.PAUSE.getCode())) > 0) {
            throw new BadResponseException(504, "您有未完成的订单");
        }

        EbRideOrder confirmRideOrder = rideOrderService.getUserConfirmOrder(agentUser.getId());
        if (confirmRideOrder != null) {
            throw new BadResponseException(505, "您有一笔订单尚未支付", confirmRideOrder);
        }

        // 人脸识别认证检查
        if(bikeAreaParam != null && !CommonConstant.ONE.equals(memberInfo.getManualAuth())){
            // 人脸识别开启时间段
            List<String> faceAuthTimeParagraphs = Arrays.asList(bikeAreaParam.getUserRideFaceAuthTimeParagraph().split(","));
            String currentHour = DateUtil.format(DateUtil.date(), "HH");
            // 开启了人脸识别认证 并且在认证时间内
            if(bikeAreaParam.getUserRideFaceAuthEnabled() && faceAuthTimeParagraphs.contains(currentHour)){
                if(memberInfo.getIsFace() == null || memberInfo.getIsFace().equals(CommonConstant.ZERO)){
                    throw new BadResponseException(519, "用户未人脸认证");
                }
                // 最后一次认证通过记录
                EbMemberFace memberFace = memberFaceService.getNewAuthFaceRecord(memberInfo.getId());
                // 人脸识别有效期
                if(memberFace != null) {
                    Integer faceAuthPassMinute = (int)DateUtil.between(memberFace.getCreateTime(), DateUtil.date(), DateUnit.MINUTE);
                    if(faceAuthPassMinute > bikeAreaParam.getUserRideFaceAuthHaveTime()) {
                        throw new BadResponseException(519, "认证已失效，请重新认证");
                    }
                }
            }
        }
    }

    @Override
    public void version(Integer id) {
        EbSettingArticle ebSettingArticle = settingArticleService.getByType(CommonConstant.ONE);
        this.update(new LambdaUpdateWrapper<EbMemberInfo>()
                .set(EbMemberInfo::getAgreementVersion,ebSettingArticle.getVersion())
                .eq(EbMemberInfo::getId,id));
    }

    @Override
    public void memberLogout(Integer id, String reason) {
        EbMemberInfo memberInfo = this.getById(id);

        // 获取骑行中 待支付订单
        EbRideOrder rideOrder = rideOrderService.getRideConfirmOrder(memberInfo.getId());
        Assert.isNull(rideOrder, "当前账号有骑行中或待支付订单");

        // 最后一次注销账号信息
        EbMemberInfo lastLogoutInfo = this.getOne(new LambdaQueryWrapper<EbMemberInfo>()
                .eq(EbMemberInfo::getIsOff, CommonConstant.ONE)
                .eq(EbMemberInfo::getMobile, memberInfo.getMobile())
                .orderByDesc(EbMemberInfo::getId)
                .last("limit 0,1"));
        // 间隔24小时
        if(lastLogoutInfo != null && lastLogoutInfo.getOffTime() != null) {
            Integer diffHour = (int)DateUtil.between(lastLogoutInfo.getOffTime(), DateUtil.date(), DateUnit.HOUR);
            if(diffHour <= 24){
                throw new BadResponseException("24小时内禁止再次注销");
            }
        }

        this.update(new LambdaUpdateWrapper<EbMemberInfo>()
                .set(EbMemberInfo::getIsOff, CommonConstant.ONE)
                .set(EbMemberInfo::getOffTime, DateUtil.date())
                .set(EbMemberInfo::getOffReason, reason)
                .eq(EbMemberInfo::getId, memberInfo.getId()));
    }

    @Override
    public EbMemberInfo getByOpenId(String openid) {
        return this.getOne(new LambdaQueryWrapper<EbMemberInfo>()
                .eq(EbMemberInfo::getOpenId, openid)
                .eq(EbMemberInfo::getIsOff, CommonConstant.ZERO)
                .eq(EbMemberInfo::getIsDeleted, CommonConstant.ZERO)
                .last("LIMIT 1"));
    }

    @Override
    public EbMemberInfo getByAliPayUserId(String aliUserId) {
        return this.getOne(new LambdaQueryWrapper<EbMemberInfo>()
                .eq(EbMemberInfo::getAlipayUserId, aliUserId)
                .eq(EbMemberInfo::getIsOff, CommonConstant.ZERO)
                .eq(EbMemberInfo::getIsDeleted, CommonConstant.ZERO)
                .last("limit 1"));
    }

    @Override
    public EbMemberInfo getByPhone(String phone) {
        return this.getOne(new LambdaQueryWrapper<EbMemberInfo>()
                .eq(EbMemberInfo::getMobile, phone)
                .eq(EbMemberInfo::getIsOff, CommonConstant.ZERO)
                .eq(EbMemberInfo::getIsDeleted, CommonConstant.ZERO)
                .last("LIMIT 1"));
    }

    @Override
    public void updateOpenId(Integer id, String openId) {
        this.update(new LambdaUpdateWrapper<EbMemberInfo>()
                .set(EbMemberInfo::getOpenId, openId)
                .eq(EbMemberInfo::getId, id));
    }

    @Override
    public void updateAliPayUserId(Integer id, String aliPayUserId) {
        this.update(new LambdaUpdateWrapper<EbMemberInfo>()
                .set(EbMemberInfo::getAlipayUserId, aliPayUserId)
                .eq(EbMemberInfo::getId, id));
    }

    @Override
    @Transactional
    public EbMemberInfo createMember(Integer areaId, String phone, String openId, String aliPayUserId, String aliPayOpenId) {
        EbMemberInfo memberInfo = new EbMemberInfo();
        memberInfo.setAreaId(areaId);
        memberInfo.setMemberNo(BillNoUtil.getDateNo("ME-", 6));
        memberInfo.setMobile(phone);
        if (StrUtil.isNotBlank(openId)) memberInfo.setOpenId(openId);
        if (StrUtil.isNotBlank(aliPayUserId)) memberInfo.setAlipayUserId(aliPayUserId);
        if (StrUtil.isNotBlank(aliPayOpenId)) memberInfo.setAlipayOpenId(aliPayOpenId);
        this.save(memberInfo);

        // 注册成功之后同步生成钱包信息 预注册会更新钱包信息
        memberWalletService.getMemberWallet(memberInfo.getId());

        memberCouponService.createByRegister(areaId, memberInfo.getId());
        // 预注册信息
        memberRegisterService.checkRegister(memberInfo.getId());
        // 骑行卡
        memberCardService.advanceGiveCard(memberInfo.getId(), memberInfo.getMobile());
        return memberInfo;
    }

    @Override
    public String getToken(EbMemberInfo memberInfo) {
        AgentInfo agentInfo = LocalMapUtil.getAgentInfo();
        AgentUser agentUser = new AgentUser();
        agentUser.setAgentId(agentInfo.getId());
        agentUser.setType(UserTypeEnum.BIKE_USER.getCode());
        agentUser.setId(memberInfo.getId());
        agentUser.setName(memberInfo.getNickname());
        agentUser.setExpireDate(DateUtil.offsetDay(new Date(), 180).getTime());

//        commonActionService.add(agentUser, "用户登陆", "", "UserLogin", ServletUtil.getUserAgent(), ServletUtil.getIp()); 20240705不存这个数据了

        // 更新用户最新版本号
        EbSettingArticle settingArticle = settingArticleService.getByType(CommonConstant.ONE);
        if(ObjectUtil.isNotNull(settingArticle)) {
            this.update(new LambdaUpdateWrapper<EbMemberInfo>()
                    .set(EbMemberInfo::getAgreementVersion, settingArticle.getVersion())
                    .eq(EbMemberInfo::getId, memberInfo.getId()));
        }

        return AgentTokenUtil.create(agentUser, agentInfo, ClientsEnum.BIKE_MEMBER_MINI).build();
    }

    @Override
    public void updateInfo(Integer id, MemberInfoUpdateForm memberInfoUpdateForm) {
        this.update(new LambdaUpdateWrapper<EbMemberInfo>()
                .set(EbMemberInfo::getNickname, memberInfoUpdateForm.getNickname())
                .set(EbMemberInfo::getHeadImgUrl, memberInfoUpdateForm.getHeadImgUrl())
                .set(memberInfoUpdateForm.getSex() != null, EbMemberInfo::getSex, memberInfoUpdateForm.getSex())
                .set(StrUtil.isNotBlank(memberInfoUpdateForm.getOpenId()), EbMemberInfo::getOpenId, memberInfoUpdateForm.getOpenId())
                .eq(EbMemberInfo::getId, id));
    }

    @Override
    public void memberAuth(Integer memberId, String name, String idCard, Integer isFace){
        this.update(new LambdaUpdateWrapper<EbMemberInfo>().set(EbMemberInfo::getName, name)
                .set(EbMemberInfo::getAuthPassTime, DateUtil.date())
                .set(EbMemberInfo::getIsFace, isFace)
                .set(EbMemberInfo::getIdCard, idCard)
                .set(EbMemberInfo::getBirthday, IdcardUtil.getBirthDate(idCard))
                .set(EbMemberInfo::getSex, IdcardUtil.getGenderByIdCard(idCard) == CommonConstant.ONE ? CommonConstant.ONE : CommonConstant.TWO)
                .eq(EbMemberInfo::getId, memberId));
    }

    @Override
    public void payDeposit(Integer memberId, BigDecimal money) {
        this.update(new LambdaUpdateWrapper<EbMemberInfo>().set(EbMemberInfo::getIsDeposit, CommonConstant.ONE)
                .set(EbMemberInfo::getDepositMoney, money)
                .eq(EbMemberInfo::getId, memberId));
    }

    @Override
    public boolean isExistThisIdCard(Integer memberId, String idCard) {
        EbMemberInfo memberInfo = this.getOne(new LambdaQueryWrapper<EbMemberInfo>()
                .eq(EbMemberInfo::getIdCard, idCard)
                .ne(memberId != null, EbMemberInfo::getId, memberId)
                .ne(EbMemberInfo::getIsOff,CommonConstant.ONE)
                .eq(EbMemberInfo::getIsEnabled, CommonConstant.ONE)
                .eq(EbMemberInfo::getIsDeleted, CommonConstant.ZERO)
                .last("limit 0,1"));
        return memberInfo != null;
    }

    @Override
    public EbMemberInfo getByAliPayOpenId(String aliOpenId) {
        return this.getOne(new LambdaQueryWrapper<EbMemberInfo>()
                .eq(EbMemberInfo::getAlipayOpenId, aliOpenId)
                .eq(EbMemberInfo::getIsOff, CommonConstant.ZERO)
                .eq(EbMemberInfo::getIsDeleted, CommonConstant.ZERO)
                .last("limit 1"));
    }

    @Override
    public void updateAliPayOpenId(Integer id, String aliPayOpenId) {
        this.update(new LambdaUpdateWrapper<EbMemberInfo>()
                .set(EbMemberInfo::getAlipayOpenId, aliPayOpenId)
                .eq(EbMemberInfo::getId, id));
    }
}
